﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConceptsFramework.ConceptResults;
using ConceptsFramework.AbstractConceptElements;
using DPLParser.DPLILCode;
using ConceptsFramework.DerivedRelationships;

namespace DPL.LogicalScript
{
    /// <summary>
    /// DPLScriptHolder contains all the DPLInstructions as DynamicConceptSetPipes
    /// </summary>
    public class DPLScriptLogicalHolder
    {
        Dictionary<string, ResultSet> ScriptVariables = new Dictionary<string, ResultSet>();
        List<IDynamicConceptSetPipe> ScriptEquations = new List<IDynamicConceptSetPipe>();
        // TemporaryResultSets are storing intermediary ResultSets for equations such as F(A) = G(B)
        // We are, indeed, splitting the equation in 2: F(A)=TEMP and G(B)=TEMP
        List<ResultSet> TemporaryResultSets = new List<ResultSet>();

        public DPLScriptLogicalHolder(DPLScript aDPLScript)
        {
            foreach (var aVariable in aDPLScript.PatternVariables)
            {
                ResultSet aVariableResultSet = new ResultSet();
                aVariableResultSet.Name = aVariable.VariableName;
                ScriptVariables.Add(aVariable.VariableName, aVariableResultSet);
            }
            foreach (var aDPLInstruction in aDPLScript.ReducedInstructions)
            {
                if (aDPLInstruction.DPLInstructionOperator is EqualsDPLOperator)
                { 
                    // CASE 1: Map the F(A) = G(B) equation
                    if ((aDPLInstruction.LeftCall != null) && (aDPLInstruction.RightCall != null))
                    {
                        ResultSet temporaryResultSet = new ResultSet();
                        TemporaryResultSets.Add(temporaryResultSet);

                        IDynamicConceptSetPipe equationLeftHand = GetDynamicPipe(aDPLInstruction.LeftCall);
                        var TempLeftVariable = ScriptVariables[aDPLInstruction.RightVariable.VariableName];
                        equationLeftHand.SetLeftVariable(ref TempLeftVariable);
                        equationLeftHand.SetRightVariable(ref temporaryResultSet);
                        ScriptEquations.Add(equationLeftHand);

                        IDynamicConceptSetPipe equationRightHand = GetDynamicPipe(aDPLInstruction.RightCall);
                        equationRightHand.SetLeftVariable(ref TempLeftVariable);
                        equationRightHand.SetRightVariable(ref temporaryResultSet);
                        ScriptEquations.Add(equationRightHand);

                    }
                    // CASE 2: Map the F(A) = B equation
                    else if ((aDPLInstruction.LeftCall != null) && (aDPLInstruction.RightCall == null))
                    {
                        IDynamicConceptSetPipe equationLeftHand = GetDynamicPipe(aDPLInstruction.LeftCall);
                        equationLeftHand.LeftVariable = ScriptVariables[aDPLInstruction.RightVariable.VariableName];

                        // ScriptVariables[aDPLInstruction.RightVariable.VariableName].CurrentSet.CollectionChanged += (a,e) => equationLeftHand.LeftVariable.CurrentSet.CollectionChanged(a,e);

                        if (!ScriptVariables.ContainsKey(aDPLInstruction.RightVariable.VariableName))
                        {
                            throw new ApplicationException("Invalid variable used in equation");
                        }

                        equationLeftHand.BindExternalResultSetToRightVariable(ScriptVariables[aDPLInstruction.RightVariable.VariableName]);
                        ScriptEquations.Add(equationLeftHand);
                    }
                    else if ((aDPLInstruction.LeftCall == null) && (aDPLInstruction.RightCall != null))
                    {
                        throw new ApplicationException("Invalid declaration");
                    }
                }
            }
        }

        

        /// <summary>
        /// Indexer to update some script variable or to read 
        /// a current script variable
        /// </summary>
        /// <param name="strVariableName"></param>
        /// <returns></returns>
        public ResultSet this[string strVariableName]
        {
            get
            {
                // This indexer is very simple, and just returns or sets
                // the corresponding element from the internal array.
                return ScriptVariables[strVariableName];
            }
            set
            {
                ScriptVariables[strVariableName].CurrentSet.Clear();
                ScriptVariables[strVariableName].CurrentSet.AddRange(value.CurrentSet);
            }
        }

     

        /// <summary>
        /// Get the IDynamicConceptSetPipe representing the F(G(H(A))) where A is a variable
        /// </summary>
        /// <param name="functionCall"></param>
        /// <param name="functionVariable"></param>
        /// <returns></returns>
        private IDynamicConceptSetPipe GetDynamicPipe(DPLFunctionCall functionCall)
        {
            if (functionCall.FunctionOperation == DPLFunctionCall.DPLOperation.CALLER)
            {
                DynamicConceptSetPipe<IsCalledByRelationship> aPipe = new DynamicConceptSetPipe<IsCalledByRelationship>();
                return aPipe;
            }
            else if (functionCall.FunctionOperation == DPLFunctionCall.DPLOperation.CONTR)
            { 
                DynamicConceptSetPipe<HostRelationship> aPipe = new DynamicConceptSetPipe<HostRelationship>();
                return aPipe;
            }
            else if (functionCall.FunctionOperation == DPLFunctionCall.DPLOperation.TYPE)
            {
                DynamicConceptSetPipe<IsTypeOfRelationship> aPipe = new DynamicConceptSetPipe<IsTypeOfRelationship>();
                return aPipe;
            }
            return null;
        }

        public List<AbstractBindableConcept> GetConcepts(string strVariableName)
        {
            return null;
        }
    }
}
